package com.example.aop.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


@Aspect
@Component
public class LogAspectj {

    private static final Logger logger = LoggerFactory.getLogger(LogAspectj.class);

    /**
     * 抽取切点表达式
     */
    @Pointcut("execution(* com.example.aop.service.OrderService.*(..))")
    public void myPointcut(){}


    @Before("myPointcut()")
    public void beforePointcut(JoinPoint joinPoint){
        logger.info("抽取切点表达式");
    }



    /**
     * 实现方法用时
     * 注解：@Around-环绕通知
     * execution:切点表达式
     * @param proceedingJoinPoint
     */
    @Around("execution(* com.example.aop.service.OrderService.*(..))")
    public void log(ProceedingJoinPoint proceedingJoinPoint){
        logger.info("【Around】环绕通知");
        // 获取当前方法参数
        Object[] args = proceedingJoinPoint.getArgs();
        logger.info("获取当前方法参数 args:{}",args);

        // 获取当前方法
        Signature signature = proceedingJoinPoint.getSignature();
        String funName = signature.getName();
        logger.info("获取当前方法 signature:{},函数名称:{}",signature, funName);

        // 记录方法用时
        long begin = System.currentTimeMillis();

        logger.info("【Around】环绕通知中的前置通知位置");

        try {
            // 实际执行的业务方法
            Object proceed = proceedingJoinPoint.proceed();

            long eng = System.currentTimeMillis();
            logger.info("方法用时：{}ms", eng - begin);
            logger.info("【Around】环绕通知中的返回通知位置");
            return;

        } catch (Throwable e) {
            logger.info("【Around】环绕通知中的异常通知位置");
            throw new RuntimeException(e);
        }
        finally {
            logger.info("【Around】环绕通知中的后置通知位置");
        }

    }

    /**
     * 前置通知
     * @param joinPoint
     */
    @Before("execution(* com.example.aop.service.OrderService.*(..))")
    public void before(JoinPoint joinPoint){
        logger.info("【before】前置通知");
        // 获取当前方法参数
        Object[] args = joinPoint.getArgs();
        logger.info("【before】获取当前方法参数 args:{}",args);

        // 获取当前方法
        Signature signature = joinPoint.getSignature();
        String funName = signature.getName();
        logger.info("【before】获取当前方法 signature:{},函数名称:{}",signature, funName);
    }

    /**
     * 后置通知
     */
    @After("execution(* com.example.aop.service.OrderService.*(..))")
    public void after(){
        logger.info("【after】后置通知");
    }

    /**
     * 异常通知
     */
    @AfterThrowing("execution(* com.example.aop.service.OrderService.*(..))")
    public void afterThrowing(){
        logger.info("【afterThrowing】异常通知");
    }

    /**
     * 返回通知
     */
    @AfterReturning("execution(* com.example.aop.service.OrderService.*(..))")
    public void afterReturning(){
        logger.info("【afterReturning】返回通知");
    }

}
